﻿using AutoMapper;
using BackData;
using CSRedis;
using Details.API.Application.Command;
using Details.API.DTOs;
using Domain;
using Infratructure.RepositoryWay;
using MD5Hash;
using MediatR;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace Details.API.Application.Handler
{
    public class UserLoginHandler : IRequestHandler<UserLoginCommand, APIResult<UserDTO>>
    {
        private readonly IRepository<UserModel> userway;
        private readonly ILogger<UserLoginHandler> log;
        private readonly IMapper mapper;
        private readonly IConfiguration configuration;
        private readonly CSRedisClient cSRedis;

        public UserLoginHandler(IRepository<UserModel> userway, ILogger<UserLoginHandler> log, IMapper mapper,IConfiguration configuration,CSRedisClient cSRedis)
        {
            this.userway = userway; // 仓储    
            this.log = log; //日志
            this.mapper = mapper;  //实体转换
            this.configuration = configuration;//获取配置文件里的密钥和其他配置信息
            this.cSRedis = cSRedis;
        }
        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="request">账号,密码</param>
        /// <param name="cancellationToken">取消</param>
        /// <returns>用户信息</returns>
        /// <exception cref="NotImplementedException"></exception>
        public Task<APIResult<UserDTO>> Handle(UserLoginCommand request, CancellationToken cancellationToken)
        {
            APIResult<UserDTO> res = new APIResult<UserDTO>();

            var user = userway.GetAll().Where(x => x.UserName == request.UserName).First();
            if (user == null)
            {         
                res.Message = $"{DateTime.UtcNow}:用户{request.UserName}登录失败,账号或密码错误";
                res.Code = StateCode.Fail;
                log.LogError(res.Message);  //错误日志
            }
            else
            {
                if (user.UserPwd == request.UserPwd.GetMD5())  //密码验证   
                {
                    res.Message = $"{DateTime.Now}:用户{request.UserName}登录成功";
                    log.LogInformation(res.Message);  //信息日志
                    res.Code = StateCode.OK;
                    res.Data = new UserDTO()
                    {
                        UserName = user.UserName,
                        RealName = user.RealName,

                        AccessToken = CreateTokenString(user.RealName, TimeSpan.FromSeconds(5)),  //短期Token
                        RefreshToken=Guid.NewGuid().ToString(),//   长期Token用于刷新短期Token,使用方式存入前端,短期过期之后作为参数,查询Redis的值是否存值,有则返回短期Token,无则返回重新登录
                       // 内容:322bce1f - 6343 - 451a - a39c - a67c0a253200样式的全球唯一标识符                   
                    };
                   cSRedis.Set(res.Data.RefreshToken,user.RealName,TimeSpan.FromDays(30));  //存入登录人真实姓名为值,未过期就用来作为刷新Token的荷载值,如果过期就提示用户重新登录
                }
                else
                {
                    res.Message = $"{DateTime.Now}:用户{request.UserName}登录失败,账号或密码错误";
                    res.Code = StateCode.Fail;
                    log.LogError(res.Message);  //错误日志
                }
            }
            return Task.FromResult(res);
        }
        /// <summary>/// 生成 JWT Token（令牌）/// </summary>/// <returns></returns>
        private string CreateTokenString(string RealName,TimeSpan? expires)
        {
            //私钥
            var secretByte = Encoding.UTF8.GetBytes(configuration["JWT:key"]);  //配置文件自定义私钥
            // 非对称加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            // 使用256 生成数字签名
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            var claims = new[] {
                new Claim("RealName" ,RealName)  //真实姓名放入荷载
            };
            // 生成Token
            var token = new JwtSecurityToken(
                issuer: configuration["JWT:issuer"], //     配置文件自定义发布者
                audience: configuration["JWT:audience"],  //  配置文件自定义订阅
                expires: expires.HasValue ? DateTime.Now.Add(expires.Value) : DateTime.UtcNow.AddMinutes(3), // 传参自定义过期时间
                signingCredentials: signingCredentials,
                claims: claims  // 荷载
            );
            // 生成token 字符串
            var strToken = new JwtSecurityTokenHandler().WriteToken(token);
            return strToken;
        }
        
    }
}
